/**
 * 
 * ETH AI GAME LIBRARY
 * 
 * Author: Michael Jaworski
 * Copyright (c) Michael Jaworski 2010
 * http://code.google.com/p/eth/
 * 
 * Licence Agreement
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *	
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

package lib.eth.systems.memory
{
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import lib.eth.core.interfaces.IRecyclable;

	/**
	 * 
	 * 
	 * 
	 */ 
	public final class EthMemory
	{		
		/**
		 * 
		 * 
		 */ 
		private var memory:Dictionary = new Dictionary ();				
		
		public function EthMemory ()
		{
		}
		
		/**
		 * gets the array containing all objects of a specific type that should be
		 * returned.
		 * 
		 * @param type the class requested - the array of objects of that type will be 
		 * returned or an empty array if that type has never been requested before.
		 * 
		 * @return an array of objects of the type specified or an empty array if the
		 * class has not been requested.
		 * 
		 */ 
		private function getTypePool (type:Class) : Array
		{
			// does type exist as a key in memory (return type pool)
			if (type in memory)
				return memory [type];
			
			// make a new type pool
			else
				return memory[type] = new Array ();
		}
		
		/**
		 * call an object of the specified type up. It must implement IRecyclable
		 * 
		 * @param type the class the object is of
		 * 
		 * @return the object itself
		 * 
		 */ 
		public function invoke (type:Class, parameter:* = null) : IRecyclable
		{
			// find the pool the object belongs to
			var typePool:Array = getTypePool (type);
			var rtn:IRecyclable;
			
			// if an object exists in the pool
			if (typePool.length > 0)
				rtn = typePool.pop () as IRecyclable;
			
			// if an object does not exist (create it and initialize)
			else
			{
				if (parameter !== null)			rtn = new type (parameter);					
				else												rtn = new type ();
			}	
			// revive the object
			rtn.revive ();
			
			// return
			return rtn;
		}
		
		/**
		 * recycle a recyclable object. You must remove any event listeners and triggers
		 * from the object so it can hibernate.
		 * 
		 * @param obj
		 * 
		 */ 
		public function recycle (obj:IRecyclable) : void
		{
			// find the pool the object belongs to
			var typeName:String = getQualifiedClassName (obj);
			var type:Class = getDefinitionByName (typeName) as Class;			
			var typePool:Array = getTypePool (type);
			
			// shutdown the object
			obj.hibernate ();
			
			// add appropriate to memory pool
			typePool.push (obj);
		}		
	}
}